package plugin

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/louloulin/dataflare/pkg/message"
	"github.com/tetratelabs/wazero"
	"github.com/tetratelabs/wazero/api"
	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

// WasmPluginLoader WASM插件加载器
type WasmPluginLoader struct {
	pluginsDir  string
	wasmRuntime wazero.Runtime // 使用wazero.Runtime
}

// NewWasmPluginLoader 创建新的WASM插件加载器
func NewWasmPluginLoader(pluginsDir string) *WasmPluginLoader {
	return &WasmPluginLoader{
		pluginsDir:  pluginsDir,
		wasmRuntime: wazero.NewRuntime(context.Background()), // 创建一个wazero运行时
	}
}

// WasmPluginDescriptor 描述WASM插件的配置
type WasmPluginDescriptor struct {
	ID          string                 `json:"id"`
	Name        string                 `json:"name"`
	Type        PluginType             `json:"type"`
	Version     string                 `json:"version"`
	APIVersion  int                    `json:"api_version"`
	Author      string                 `json:"author"`
	Description string                 `json:"description"`
	EntryPoint  string                 `json:"entry_point"`
	Config      map[string]interface{} `json:"config"`
	WasmPath    string                 `json:"wasm_path"`
}

// WasmPlugin represents a WebAssembly plugin
type WasmPlugin struct {
	id           string
	name         string
	pluginType   PluginType
	description  string
	version      string
	filePath     string
	started      bool
	initialized  bool
	processMutex sync.Mutex
	wasmMemory   *WasmMemory
	config       *PluginConfig

	// 使用具体的wazero类型
	runtime  wazero.Runtime
	module   wazero.CompiledModule
	instance api.Module

	// 导出的函数
	initializeFunc api.Function
	startFunc      api.Function
	stopFunc       api.Function
	processFunc    api.Function
	getVersionFunc api.Function
	getAPIVersion  api.Function

	// 内存管理函数
	allocateFunc   api.Function
	deallocateFunc api.Function

	// 清理函数
	closeFunc func()
}

// NewWasmPlugin creates a new WebAssembly plugin
func NewWasmPlugin(id string, pluginType PluginType, filePath string) *WasmPlugin {
	plugin := &WasmPlugin{
		id:          id,
		pluginType:  pluginType,
		filePath:    filePath,
		description: "WebAssembly Plugin",
		version:     "1.0.0",
		initialized: false,
		started:     false,
		runtime:     wazero.NewRuntime(context.Background()),
	}
	return plugin
}

// GetID returns the plugin ID
func (p *WasmPlugin) ID() string {
	return p.id
}

// GetType returns the plugin type
func (p *WasmPlugin) Type() PluginType {
	return p.pluginType
}

// GetDescription returns the plugin description
func (p *WasmPlugin) GetDescription() string {
	return p.description
}

// GetVersion returns the plugin version
func (p *WasmPlugin) Version() string {
	return p.version
}

// GetInfo returns information about the plugin
func (p *WasmPlugin) GetInfo() PluginInfo {
	return PluginInfo{
		ID:          p.id,
		Name:        p.id,
		Type:        p.pluginType,
		Mode:        PluginModeWasm,
		Version:     p.version,
		Description: p.description,
		APIVersion:  1,
		Author:      "DataLink",
		License:     "",
		Homepage:    "",
		Config:      nil,
	}
}

// Initialize initializes the plugin
func (p *WasmPlugin) Init(ctx context.Context, config *PluginConfig) error {
	if p.initialized {
		return fmt.Errorf("plugin already initialized")
	}

	p.config = config

	// 读取WASM文件
	wasmBytes, err := os.ReadFile(p.filePath)
	if err != nil {
		return fmt.Errorf("failed to read WASM file: %w", err)
	}

	// 配置WASI
	p.runtime = wazero.NewRuntime(ctx)
	wasi_snapshot_preview1.MustInstantiate(ctx, p.runtime)

	// 编译WASM模块
	p.module, err = p.runtime.CompileModule(ctx, wasmBytes)
	if err != nil {
		return fmt.Errorf("failed to compile WASM module: %w", err)
	}

	// 实例化WASM模块
	p.instance, err = p.runtime.InstantiateModule(ctx, p.module, wazero.NewModuleConfig())
	if err != nil {
		return fmt.Errorf("failed to instantiate WASM module: %w", err)
	}

	// 获取导出的函数
	p.initializeFunc = p.instance.ExportedFunction("initialize")
	p.startFunc = p.instance.ExportedFunction("start")
	p.stopFunc = p.instance.ExportedFunction("stop")
	p.processFunc = p.instance.ExportedFunction("process")
	p.getVersionFunc = p.instance.ExportedFunction("get_version")
	p.getAPIVersion = p.instance.ExportedFunction("get_api_version")
	p.allocateFunc = p.instance.ExportedFunction("allocate")
	p.deallocateFunc = p.instance.ExportedFunction("deallocate")

	p.initialized = true
	return nil
}

// Start starts the plugin
func (p *WasmPlugin) Start(ctx context.Context) error {
	if !p.initialized {
		return fmt.Errorf("plugin not initialized")
	}

	if p.started {
		return nil
	}

	// 调用start函数
	if p.startFunc != nil {
		results, err := p.startFunc.Call(ctx)
		if err != nil {
			return fmt.Errorf("error calling start function: %w", err)
		}

		if len(results) > 0 && results[0] != 0 {
			return fmt.Errorf("start function returned error code: %d", results[0])
		}
	}

	fmt.Printf("WASM插件 %s 启动成功\n", p.id)
	p.started = true
	return nil
}

// Stop stops the plugin
func (p *WasmPlugin) Stop(ctx context.Context) error {
	if !p.started {
		return nil
	}

	// 调用stop函数
	if p.stopFunc != nil {
		results, err := p.stopFunc.Call(ctx)
		if err != nil {
			return fmt.Errorf("error calling stop function: %w", err)
		}

		if len(results) > 0 && results[0] != 0 {
			return fmt.Errorf("stop function returned error code: %d", results[0])
		}
	}

	fmt.Printf("WASM插件 %s 停止成功\n", p.id)
	p.started = false

	// 关闭WASM资源
	if p.closeFunc != nil {
		p.closeFunc()
	}

	return nil
}

// Process processes the input message
func (p *WasmPlugin) Process(ctx context.Context, input message.DataMessage) (message.DataMessage, error) {
	if !p.started {
		return nil, fmt.Errorf("plugin not started")
	}

	p.processMutex.Lock()
	defer p.processMutex.Unlock()

	// 调用实际的处理实现
	return p.RealProcessImpl(ctx, input)
}

// LoadWasmPlugins loads all WebAssembly plugins from a directory
func LoadWasmPlugins(ctx context.Context, directory string) ([]Plugin, error) {
	var plugins []Plugin

	// 确保目录存在
	if _, err := os.Stat(directory); os.IsNotExist(err) {
		return plugins, nil
	}

	// 遍历目录
	err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 检查是否是.wasm文件
		if !info.IsDir() && filepath.Ext(path) == ".wasm" {
			// 从文件名获取插件ID
			id := filepath.Base(path)
			id = id[:len(id)-len(filepath.Ext(id))]

			// 创建插件
			plugin := NewWasmPlugin(id, PluginTypeProcessor, path)

			// 初始化插件
			if err := plugin.Init(ctx, nil); err != nil {
				fmt.Printf("Error initializing WASM plugin %s: %v\n", id, err)
				return nil
			}

			plugins = append(plugins, plugin)
		}

		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("error loading WASM plugins: %w", err)
	}

	return plugins, nil
}

// ProcessorWasmPlugin 处理器WASM插件
type ProcessorWasmPlugin struct {
	*WasmPlugin
}

// NewProcessorWasmPlugin 创建新的处理器WASM插件
func NewProcessorWasmPlugin(descriptor WasmPluginDescriptor) *ProcessorWasmPlugin {
	plugin := &ProcessorWasmPlugin{
		WasmPlugin: NewWasmPlugin(descriptor.ID, descriptor.Type, descriptor.WasmPath),
	}

	return plugin
}

// LoadWasmPlugins 从目录加载所有WASM插件
func (l *WasmPluginLoader) LoadWasmPlugins(ctx context.Context) ([]Plugin, error) {
	// 确保插件目录存在
	if _, err := os.Stat(l.pluginsDir); os.IsNotExist(err) {
		fmt.Printf("Creating plugins directory: %s\n", l.pluginsDir)
		if err := os.MkdirAll(l.pluginsDir, 0755); err != nil {
			return nil, fmt.Errorf("failed to create plugins directory: %w", err)
		}
	}

	// 读取插件目录
	files, err := os.ReadDir(l.pluginsDir)
	if err != nil {
		return nil, fmt.Errorf("failed to read plugins directory: %w", err)
	}

	var plugins []Plugin
	// 遍历所有.json描述文件
	for _, file := range files {
		if file.IsDir() || filepath.Ext(file.Name()) != ".json" {
			continue
		}

		// 读取描述文件
		descriptorPath := filepath.Join(l.pluginsDir, file.Name())
		descriptor, err := l.readPluginDescriptor(descriptorPath)
		if err != nil {
			fmt.Printf("Error reading plugin descriptor %s: %v\n", descriptorPath, err)
			continue
		}

		// 检查WASM文件是否存在
		wasmPath := filepath.Join(l.pluginsDir, descriptor.EntryPoint)
		if _, err := os.Stat(wasmPath); os.IsNotExist(err) {
			fmt.Printf("WASM file not found: %s\n", wasmPath)
			continue
		}

		// 设置WASM文件路径
		descriptor.WasmPath = wasmPath

		// 创建插件
		plugin, err := LoadWasmPlugin(ctx, descriptor)
		if err != nil {
			fmt.Printf("Error loading WASM plugin %s: %v\n", descriptor.ID, err)
			continue
		}

		plugins = append(plugins, plugin)
	}

	return plugins, nil
}

// readPluginDescriptor 读取插件描述文件
func (l *WasmPluginLoader) readPluginDescriptor(path string) (WasmPluginDescriptor, error) {
	var descriptor WasmPluginDescriptor

	// 读取文件内容
	data, err := os.ReadFile(path)
	if err != nil {
		return descriptor, fmt.Errorf("failed to read plugin descriptor: %w", err)
	}

	// 解析JSON
	if err := json.Unmarshal(data, &descriptor); err != nil {
		return descriptor, fmt.Errorf("failed to parse plugin descriptor: %w", err)
	}

	// 验证必填字段
	if descriptor.ID == "" {
		return descriptor, fmt.Errorf("plugin ID is required")
	}
	if descriptor.Type == "" {
		return descriptor, fmt.Errorf("plugin type is required")
	}
	if descriptor.EntryPoint == "" {
		return descriptor, fmt.Errorf("plugin entry point is required")
	}

	return descriptor, nil
}

// CreateExampleWasmPlugin 创建示例WASM插件配置文件
func (l *WasmPluginLoader) CreateExampleWasmPlugin(pluginsDir string) error {
	// 确保插件目录存在
	if _, err := os.Stat(pluginsDir); os.IsNotExist(err) {
		if err := os.MkdirAll(pluginsDir, 0755); err != nil {
			return fmt.Errorf("failed to create plugins directory: %w", err)
		}
	}

	// 示例插件描述符
	examplePlugin := WasmPluginDescriptor{
		ID:          "example-processor",
		Name:        "Example Processor",
		Type:        PluginTypeProcessor,
		Version:     "1.0.0",
		APIVersion:  1,
		Author:      "DataLink Team",
		Description: "An example processor plugin",
		EntryPoint:  "example-processor.wasm",
		Config: map[string]interface{}{
			"timeout":    5000,
			"retries":    3,
			"debugMode":  true,
			"bufferSize": 1024,
		},
	}

	// 序列化为JSON
	jsonData, err := json.MarshalIndent(examplePlugin, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to serialize plugin descriptor: %w", err)
	}

	// 写入文件
	filename := filepath.Join(pluginsDir, "example-processor.json")
	if err := os.WriteFile(filename, jsonData, 0644); err != nil {
		return fmt.Errorf("failed to write plugin descriptor: %w", err)
	}

	// 创建dummy WASM文件示例
	dummyWasmFile := filepath.Join(pluginsDir, "example-processor.wasm")
	dummyContent := []byte("This is just a placeholder for a real WASM file.")
	if err := os.WriteFile(dummyWasmFile, dummyContent, 0644); err != nil {
		return fmt.Errorf("failed to write dummy WASM file: %w", err)
	}

	fmt.Printf("Created example WASM plugin descriptor: %s\n", filename)
	fmt.Printf("Created dummy WASM file: %s\n", dummyWasmFile)
	fmt.Println("In a real-world scenario, you would compile your plugin to WebAssembly.")

	return nil
}

// LoadWasmPlugin 从WASM插件描述符加载插件
func LoadWasmPlugin(ctx context.Context, descriptor WasmPluginDescriptor) (Plugin, error) {
	// 创建插件
	var plugin Plugin

	// 根据插件类型创建不同的插件实现
	switch descriptor.Type {
	case PluginTypeProcessor:
		plugin = NewProcessorWasmPlugin(descriptor)
	default:
		plugin = NewWasmPlugin(descriptor.ID, descriptor.Type, descriptor.WasmPath)
	}

	// 配置
	config := make(map[string]interface{})
	if descriptor.Config != nil {
		for k, v := range descriptor.Config {
			config[k] = v
		}
	}

	// 设置WASM文件路径
	wasmPath := descriptor.WasmPath
	if wasmPath == "" && descriptor.EntryPoint != "" {
		wasmPath = descriptor.EntryPoint
	}

	if wasmPath == "" {
		return nil, fmt.Errorf("missing wasm file path for plugin %s", descriptor.ID)
	}

	config["wasm_path"] = wasmPath

	// 初始化插件
	if err := plugin.Init(ctx, nil); err != nil {
		fmt.Printf("Error initializing plugin %s: %v\n", descriptor.ID, err)
		return nil, err
	}

	return plugin, nil
}

// Config returns the plugin configuration
func (p *WasmPlugin) Config() *PluginConfig {
	return p.config
}

// Description returns the plugin description
func (p *WasmPlugin) Description() string {
	return p.description
}

// Name returns the plugin name
func (p *WasmPlugin) Name() string {
	return p.name
}

// Pause pauses the plugin
func (p *WasmPlugin) Pause(ctx context.Context) error {
	// WASM plugins don't support pause operation
	return fmt.Errorf("pause operation not supported for WASM plugins")
}

// Resume resumes the plugin
func (p *WasmPlugin) Resume(ctx context.Context) error {
	// WASM plugins don't support resume operation
	return fmt.Errorf("resume operation not supported for WASM plugins")
}

// Validate validates the plugin configuration
func (p *WasmPlugin) Validate(config *PluginConfig) error {
	// Add validation logic here
	return nil
}

// Status returns the current status of the plugin
func (p *WasmPlugin) Status() PluginStatus {
	if !p.initialized {
		return StatusCreated
	}
	if p.started {
		return StatusRunning
	}
	return StatusStopped
}
